<?php
namespace Zeeging;


/*
{
    "require": {
        "sop/asn1": "^3.3",
        "sop/crypto-encoding": "^0.2.0",
        "sop/crypto-types": "^0.2.1",
        "kornrunner/keccak": "^1.0",
        "symfony/dotenv": "^4.0"
    }
}
*/

use Sop\CryptoTypes\Asymmetric\EC\ECPublicKey;
use Sop\CryptoTypes\Asymmetric\EC\ECPrivateKey;
use Sop\CryptoEncoding\PEM;
use kornrunner\Keccak;

Class EthereumWallet{

	public static function generate(){
		$config = [
		    'private_key_type' => OPENSSL_KEYTYPE_EC,
		    'curve_name' => 'secp256k1',
		    'config' => __DIR__.DIRECTORY_SEPARATOR.'openssl.cnf'
		];
		$res = openssl_pkey_new($config);
		if (!$res) {
		    echo 'ERROR: Fail to generate private key. -> ' . openssl_error_string();
		    // exit;
		}
		// 生成私钥
		openssl_pkey_export($res, $priv_key);
		// 获取公钥
		$key_detail = openssl_pkey_get_details($res);
		$pub_key = $key_detail["key"];
		$priv_pem = PEM::fromString($priv_key);
		// 转换为椭圆曲线私钥格式
		$ec_priv_key = ECPrivateKey::fromPEM($priv_pem);
		// 然后将其转换为ASN1结构
		$ec_priv_seq = $ec_priv_key->toASN1();
		// HEX中的私钥和公钥
		$priv_key_hex = bin2hex($ec_priv_seq->at(1)->asOctetString()->string());
		$priv_key_len = strlen($priv_key_hex) / 2;
		$pub_key_hex = bin2hex($ec_priv_seq->at(3)->asTagged()->asExplicit()->asBitString()->string());
		$pub_key_len = strlen($pub_key_hex) / 2;
		// 从公钥导出以太坊地址
		// 每个EC公钥始终以0x04开头，
		// 我们需要删除前导0x04才能正确hash它
		$pub_key_hex_2 = substr($pub_key_hex, 2);
		$pub_key_len_2 = strlen($pub_key_hex_2) / 2;
		// Hash
		$hash = Keccak::hash(hex2bin($pub_key_hex_2), 256);
		// 以太坊地址长度为20个字节。 （40个十六进制字符长）
		// 我们只需要最后20个字节作为以太坊地址
		$wallet_address = '0x' . substr($hash, -40);
		$wallet_private_key = '0x' . $priv_key_hex;
		// echo "\r\n   ETH Wallet Address: " . $wallet_address;
		// echo "\r\n   Private Key: " . $wallet_private_key;

		return (object)[
			"private"=>$wallet_private_key,
			"address"=>$wallet_address
		];
	}
}

// print_r(EthereumWallet::generate());








